package db

import (
	"errors"
	"fmt"
	_ "gitee.com/chunanyong/dm"
	_ "github.com/go-sql-driver/mysql"
	"github.com/simplechain-org/client/log"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"net/url"
	"strings"
	"time"
	"xorm.io/xorm"
	sqlLog "xorm.io/xorm/log"
)

type Config struct {
	DriverName string `yaml:"driverName"`
	Database   string `yaml:"database"`
	Host       string `yaml:"host"`
	User       string `yaml:"user"`
	Password   string `yaml:"password"`
	LogLevel   string `yaml:"logLevel"`
	ShowSQL    bool   `yaml:"showSQL"`
	MaxIdle    int    `yaml:"maxIdle"`
	MaxOpen    int    `yaml:"maxOpen"`
	//字符编码
	Charset string `yaml:"charset"`
	//是否转化时间
	ParseTime bool `yaml:"parseTime"`
	//时区设置
	Loc string `yaml:"loc"`
}

type ConfigOnline struct {
	BankName string `yaml:"bankName"`
	Host     string `yaml:"host"`
	Database string `yaml:"database"`
	User     string `yaml:"user"`
	Password string `yaml:"password"`
}

func loadConfig(file string) *Config {
	data, err := ioutil.ReadFile(file)
	if err != nil {
		log.Error(err.Error())
		return nil
	}
	var config Config
	err = yaml.Unmarshal(data, &config)
	if err != nil {
		log.Error(err.Error())
	}
	return &config
}

func NewDBWithConfig(configFile string) (*xorm.Engine, error) {
	config := loadConfig(configFile)
	return New(config)
}

func New(config *Config) (*xorm.Engine, error) {
	var dsn string
	switch strings.ToLower(config.DriverName) {
	case "mysql":
		format := "%s:%s@tcp(%s)/%s?charset=%s&parseTime=%v&loc=%s"
		dsn = fmt.Sprintf(format, config.User, config.Password, config.Host, config.Database, config.Charset, config.ParseTime, url.QueryEscape(config.Loc))
	default:
		return nil, errors.New("DriverName is not supported")
	}

	log.Info("initialized db:", "dsn=", dsn)
	engine, err := xorm.NewEngine(strings.ToLower(config.DriverName), dsn)
	if err != nil {
		return nil, err
	}
	// 打印sql
	logger := &logger{
		showSQL: config.ShowSQL,
		level:   level(config.LogLevel),
	}
	engine.SetLogger(logger)
	engine.ShowSQL(config.ShowSQL)
	engine.SetMaxIdleConns(config.MaxIdle)
	engine.SetMaxOpenConns(config.MaxOpen)
	//连接生存时间半个小时
	engine.SetConnMaxLifetime(1800 * time.Second)

	err = engine.Ping()
	if err != nil {
		return nil, err
	}
	return engine, nil
}

func NewOnlineList(configList []ConfigOnline, config *Config) (dbOnlineList []*xorm.Engine, err error) {
	for i, configOnline := range configList {
		newConfig := Config{
			DriverName: "mysql",
			Database:   configOnline.Database,
			Host:       configOnline.Host,
			User:       configOnline.User,
			Password:   configOnline.Password,
			LogLevel:   config.LogLevel,
			ShowSQL:    config.ShowSQL,
			MaxIdle:    config.MaxIdle,
			MaxOpen:    config.MaxOpen,
			Charset:    config.Charset,
			ParseTime:  config.ParseTime,
			Loc:        config.Loc,
		}
		engine, err2 := New(&newConfig)
		if err2 != nil {
			log.Error("NewOnlineList", "index", i, "configOnline", configOnline)
			err = err2
			return
		}
		dbOnlineList = append(dbOnlineList, engine)
	}
	return
}

func level(level string) sqlLog.LogLevel {
	switch strings.ToUpper(level) {
	case "DEBUG":
		return sqlLog.LOG_DEBUG
	case "INFO":
		return sqlLog.LOG_INFO
	case "WARNING":
		return sqlLog.LOG_WARNING
	case "ERROR":
		return sqlLog.LOG_ERR
	case "OFF":
		return sqlLog.LOG_OFF
	case "UNKNOWN":
		return sqlLog.LOG_UNKNOWN
	default:
		return sqlLog.LOG_INFO
	}
}
